package com.fzs.webadb.service.impl;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.fzs.webadb.config.AdbProperties;
import com.fzs.webadb.constant.ConstantPool;
import com.fzs.webadb.pojo.PtyConnectInfo;
import com.fzs.webadb.pojo.WebSSHData;
import com.fzs.webadb.service.WebSSHService;
import com.pty4j.PtyProcess;
import com.pty4j.WinSize;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* @Description: WebSSH业务逻辑实现
* @Author: NoCortY
* @Date: 2020/3/8
*/
@Service
public class WebSSHServiceImpl implements WebSSHService {
    //存放adb connect连接信息的map
    private static Map<String, Object> adbConnectMap = new ConcurrentHashMap<>();

    //存放adb shell连接信息的map
    private static Map<String, PtyProcess> adbShellMap = new ConcurrentHashMap<>();

    //存放用户输入信息缓冲区
    private static Map<Object, String> userBuffer = new ConcurrentHashMap<Object, String>();

    private Logger logger = LoggerFactory.getLogger(WebSSHServiceImpl.class);
    //线程池
    private ExecutorService executorService = Executors.newCachedThreadPool();

    @Resource
    private AdbProperties adbProperties;


    @Override
    @PostConstruct
    public void initAdbProcess() {
        try {
            Process connect = new ProcessBuilder("adb", "start-server")
                    .directory(new File(adbProperties.getAdbPath()))
                    .redirectErrorStream(true)
                    .start();
            logger.info("开启启动adb进程");
            connect.waitFor();
            logger.info("adb进程启动成功");
        } catch (IOException | InterruptedException e) {
            logger.error("adb进程启动失败",e);
        }
    }

    /**
     * @Description: 初始化连接
     * @Param: [session]
     * @return: void
     * @Author: NoCortY
     * @Date: 2020/3/7
     */
    @Override
    public void initAdbConnection(WebSocketSession session) {
        try {
            String[] cmd = {"adb", "connect", "183.240.23.14:37223"};
            PtyProcess shell = PtyProcess.exec(cmd, null, adbProperties.getAdbPath());
            shell.setWinSize(new WinSize(80, 24));
            String uuid = String.valueOf(session.getAttributes().get(ConstantPool.USER_UUID_KEY));
            PtyConnectInfo ptyConnectInfo = new PtyConnectInfo();
            ptyConnectInfo.setWebSocketSession(session);
            ptyConnectInfo.setPtyProcess(shell);
            adbConnectMap.put(uuid, ptyConnectInfo);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


    }

    /**
     * @Description: 处理客户端发送的数据
     * @Param: [buffer, session]
     * @return: void
     * @Author: NoCortY
     * @Date: 2020/3/7
     */
    @Override
    public void recvHandle(String buffer, WebSocketSession session) {
        ObjectMapper objectMapper = new ObjectMapper();
        WebSSHData webSSHData = null;
        try {
            webSSHData = objectMapper.readValue(buffer, WebSSHData.class);
        } catch (IOException e) {
            logger.error("Json转换异常");
            logger.error("异常信息:{}", e.getMessage());
            return;
        }
        String userId = String.valueOf(session.getAttributes().get(ConstantPool.USER_UUID_KEY));
        if (ConstantPool.WEBSSH_OPERATE_CONNECT.equals(webSSHData.getOperate())) {

            PtyConnectInfo ptyConnectInfo = (PtyConnectInfo) adbConnectMap.get(userId);
            WebSSHData finalWebSSHData = webSSHData;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        connectToDevices(ptyConnectInfo.getPtyProcess(), session, finalWebSSHData.getCols(), finalWebSSHData.getRows(),userId);
//                        if (sshConnectInfo.getChannel().isClosed()) {
//                            close(session);
//                        }
                    } catch (IOException e) {
                        logger.error("webssh连接异常");
                        logger.error("异常信息:{}", e.getMessage());
                        try {
                            //发送错误信息
                            sendMessage(session, ("ERROR : "+e.getMessage()).getBytes());
                        } catch (IOException ex) {
                            logger.error("消息发送失败");
                            logger.error("异常信息:{}", ex.getMessage());
                        }
                        close(session);
                    }
                }
            });
        } else if (ConstantPool.WEBSSH_OPERATE_COMMAND.equals(webSSHData.getOperate())) {
            // 根据用户id创建缓冲区
            String command = webSSHData.getCommand();
            // 识别到删除键情况
//            if (command.equals("\b")) {
//
//            }

            // 识别到tab情况
            // 未识别回车时,存入缓冲区,识别到回车
//            String userBufferOrDefault = userBuffer.getOrDefault(userId, "");
//            String concat = userBufferOrDefault.concat(command);
//
//
//            // 识别到tab情况
//
//            if (!command.equals("\r")) {
//
//                userBuffer.put(userId, concat);
//                try {
//                    sendMessage(session, command.getBytes());
//                } catch (IOException e) {
//                    throw new RuntimeException(e);
//
//                }
//                // 模拟异常命令
//                if (concat.equals("reboot")){
//                    close(session);
//                }
//                // 模拟缓冲区占满
////                if (concat.length() <= 5){
////                    return;
////                }
//                return;
//            }
//            command = concat;


            PtyProcess ptyProcess  = adbShellMap.get(userId);
            try {
                transToDevices(ptyProcess, command);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
//            if (sshConnectInfo != null) {
//                try {
//                    ChannelShell channel = (ChannelShell) sshConnectInfo.getChannel();
//                    if (channel != null) {
//                        channel.setPtySize(webSSHData.getCols(),webSSHData.getRows(),webSSHData.getWidth(),webSSHData.getHeight());
//                        transToDevices(ptyProcess, command);
//                        userBuffer.remove(userId);
//                        if (channel.isClosed()) {
//                            close(session);
//                        }
//                    }
//                } catch (IOException e) {
//                    logger.error("webssh连接异常");
//                    logger.error("异常信息:{}", e.getMessage());
//                    try {
//                        //发送错误信息
//                        sendMessage(session, ("ERROR : "+e.getMessage()).getBytes());
//                    } catch (IOException ex) {
//                        logger.error("消息发送失败");
//                        logger.error("异常信息:{}", ex.getMessage());
//                    }
//                    close(session);
//                }
//            }
        } else if (ConstantPool.WEBSSH_OPERATE_HEARTBEAT.equals(webSSHData.getOperate())) {
            //检查心跳
//            SSHConnectInfo sshConnectInfo = (SSHConnectInfo) sshMap.get(userId);
//            if (sshConnectInfo != null) {
//                try {
//                    //处于连接状态则发送健康数据，不能为空，空则断开连接。
//                    if (sshConnectInfo.getChannel().isConnected())
//                        sendMessage(session, "Heartbeat healthy".getBytes());
//                } catch (IOException e) {
//                    logger.error("消息发送失败");
//                    logger.error("异常信息:{}", e.getMessage());
//                }
//            }
        } else {
            logger.error("不支持的操作");
            close(session);
        }
    }

    @Override
    public void sendMessage(WebSocketSession session, byte[] buffer) throws IOException {
        session.sendMessage(new TextMessage(buffer));
    }

    @Override
    public void close(WebSocketSession session) {
        String userId = String.valueOf(session.getAttributes().get(ConstantPool.USER_UUID_KEY));
        PtyConnectInfo ptyConnectInfo = (PtyConnectInfo) adbConnectMap.get(userId);
        if (ptyConnectInfo != null) {
            //断开连接
            try {
                PtyProcess ptyProcess = ptyConnectInfo.getPtyProcess();
                String[] cmd = {"adb", "disconnect", "183.240.23.14:37223"};
                ptyProcess.exec(cmd, null, adbProperties.getAdbPath());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            //map中移除
            adbConnectMap.remove(userId);
            adbShellMap.remove(userId);
            userBuffer.remove(userId);
        }
        try {
            session.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



    private void transToDevices(PtyProcess ptyProcess, String command) throws IOException {
        if (ptyProcess != null) {
            OutputStream outputStream = ptyProcess.getOutputStream();
            outputStream.write(command.getBytes());
            outputStream.flush();
        }
    }

    private void connectToDevices(PtyProcess ptyProcess, WebSocketSession webSocketSession,int cols,int rows,String userId) throws IOException {
        String[] cmd = {"adb", "-s", "183.240.23.14:37223", "shell"};
        PtyProcess shell = ptyProcess.exec(cmd, null, adbProperties.getAdbPath());
        shell.setWinSize(new WinSize(cols, rows));
        adbShellMap.put(userId, shell);
        //读取终端返回的信息流
        InputStream inputStream = shell.getInputStream();
//        String a = "welcome";
//        InputStream inputStream = new ByteArrayInputStream(a.getBytes());
        try {
            //循环读取
            byte[] buffer = new byte[1024];
            int i = 0;
            //如果没有数据来，线程会一直阻塞在这个地方等待数据。

            while ((i = inputStream.read(buffer)) != -1) {
                // 每次重连时丢弃首次缓冲区数据
//                if (countDownLatch.getCount() > 0){
//                    countDownLatch.countDown();
//                    buffer = new byte[1024];
//                    String s = new String(buffer);
//                    logger.info(s);
//                    sendMessage(webSocketSession, Arrays.copyOfRange(a.getBytes(), 0, i));
//                    continue;
//                }
                sendMessage(webSocketSession, Arrays.copyOfRange(buffer, 0, i));
            }

        } finally {

            if (inputStream != null) {
                inputStream.close();
            }
        }

    }

}
